package com.blueocean_health.care.management.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.blueocean_health.care.management.common.LocalManager;
import com.blueocean_health.care.management.common.base.string.StringUtils;
import com.blueocean_health.care.management.domain.base.Role;
import com.blueocean_health.care.management.domain.base.Team;
import com.blueocean_health.care.management.domain.base.TeamModule;
import com.blueocean_health.care.management.domain.base.UserAccount;
import com.blueocean_health.care.management.domain.base.UserTeam;
import com.blueocean_health.care.management.domain.dto.TeamListDto;
import com.blueocean_health.care.management.domain.vo.LoginDataVo;
import com.blueocean_health.care.management.domain.vo.OrganizationVo;
import com.blueocean_health.care.management.domain.vo.ProjectVo;
import com.blueocean_health.care.management.domain.vo.TeamVo;
import com.blueocean_health.care.management.em.LocalManagerType;
import com.blueocean_health.care.management.em.ModuleStatusEnum;
import com.blueocean_health.care.management.em.ProjectManagerKeyEnum;
import com.blueocean_health.care.management.em.ProjectTypeEnum;
import com.blueocean_health.care.management.em.RoleTypeEnum;
import com.blueocean_health.care.management.em.TeamTypeEnum;
import com.blueocean_health.care.management.exception.OrganizationException;
import com.blueocean_health.care.management.exception.ProjectException;
import com.blueocean_health.care.management.mapper.TeamMapper;
import com.blueocean_health.care.management.mapper.TeamModuleMapper;
import com.blueocean_health.care.management.mapper.UserTeamMapper;
import com.blueocean_health.care.management.service.OrgAndProjectService;
import com.blueocean_health.care.management.service.ProjectService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

/**
* 项目service 
* @author huyanqiu
* @date 2018年3月21日 下午6:28:07
* @version 版本号：1.0
*/
@Service
public class ProjectServiceImpl implements ProjectService{
	
	@Autowired
	private TeamMapper teamMapper;
	@Autowired
	private TeamModuleMapper teamModuleMapper;
	@Autowired
	private UserTeamMapper userTeamMapper;
	@Autowired
	private OrgAndProjectService orgAndProjectService;
	
	// 医院图片存储路径
	@Value("${service.address.hospitalpic}")
	private String serviceAddressHospitalpic;
	
	// 禁用
	private static final int disable = 2;
	// 启用
	private static final int enable = 1;
	// 删除
	private static final int delete = 3;
	
	/**
	 * 创建项目
	 * 1、当前登录人所属组织是否有创建权限
	 * 2、层次结构组织有5级（上级组织层级<=5即可），（组织下面可以挂项目即共有6级）
	 * 3、 同级组织名称唯一
	 * 4、保存（组织基本信息以及组织和模块的关联关系）
	 */
	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public void add(ProjectVo projectVo) {
		// 项目所属组织
		Team org = teamMapper.findOrgById(projectVo.getOrgId());
		// 校验信息
		checkAddProject(projectVo, org);
		// 为了防止并发新增组织和项目，发生计算的code重复问题；5次请求后还是重复则返回异常信息。
		boolean flag = true;
		int times = 1;
		while(flag && times<=5) {
			try {
				// 保存项目
				save(projectVo, org);
				flag = false;
			} catch(DuplicateKeyException e) { 
				e.printStackTrace();
				if (times==5) {
					flag = true;
				}
			} finally {
				times++;
			}
		}
		// code不唯一
		if (times>=6) {
			throw new ProjectException("请重新点击保存按钮");
		}
	}
	
	/**
	 * 编辑项目
	 */
	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public void modify(ProjectVo projectVo) {
		Team team = teamMapper.selectByPrimaryKey(projectVo.getId());
		// 校验编辑项目参数
		checkEditProject(projectVo, team);
		// 更新项目信息
		updateProject(projectVo, team);
		// 更新项目经理
		Map<String, String> paramsMap = new HashMap<>();
		paramsMap.put("teamId", projectVo.getId()+"");
		paramsMap.put("manager", projectVo.getManager());
		paramsMap.put("category", ProjectManagerKeyEnum._2.getKey());
		orgAndProjectService.updateManager(paramsMap);
	}
	
	/**
	 * 删除项目
	 */
	@Override
	public void delete(Integer id) {
		// 指定项目
		Team team = teamMapper.selectByPrimaryKey(id);
		if (StringUtils.isEmpty(team)) {
//			throw new OrganizationException("指定项目不存在");
			return;
		}
		if (delete==team.getIsActive()) {
//			throw new OrganizationException("指定项目已被删除");
			return;
		}
		// 1、判断是否有关联的角色
		// 1.1、该组织是否存在授权信息（通用角色中是否存在该组织的用户<过滤该组织对应的负责人>，自建角色授权）
		Role role = orgAndProjectService.getManagerPublicRole(ProjectManagerKeyEnum._2.getKey());
		Map<String, String> paramsMap = new HashMap<>();
		paramsMap.put("id", id+""); // 组织id
		paramsMap.put("roleId", role.getRoleId()+""); // 角色id
		paramsMap.put("category", ProjectManagerKeyEnum._2.getKey()); // 角色id
		paramsMap.put("roleStatus", role.getIsActive()+""); // 角色状态
		List<UserTeam> roleAuthList = teamMapper.isExistRoleAuth(paramsMap);
		if (!roleAuthList.isEmpty()) {
			throw new OrganizationException("该项目存在关联数据，不允许删除");
		}
		// 1.2、是否存在自建角色
		List<Role> roleList = teamMapper.isExistRelationRole(id);
		if (!roleList.isEmpty()) {
			throw new OrganizationException("该项目存在关联数据，不允许删除");
		}
		// 1.3、是否存在用户
		List<UserAccount> userAccount = teamMapper.isExistUserAccount(String.valueOf(id));
		if (!userAccount.isEmpty()) {
			throw new OrganizationException("该项目存在关联数据，不允许删除");
		}
		// 2、删除
		// 2.1、删除项目--逻辑删除
		teamMapper.updateTeamStatusByRoId(id, delete);
		// 2.2、更新项目模块中间表状态--逻辑删除
		teamModuleMapper.updateTeamModuleStatusByRoId(id, delete);
		// 2.3、删除项目和角色项目经理关系(user_team)--物理删除
		paramsMap.put("roleId", role.getRoleId()+"");
		paramsMap.put("teamId", id+"");
		paramsMap.put("status", role.getIsActive()+"");
		paramsMap.put("category", ProjectManagerKeyEnum._2.getKey());
		teamMapper.deleteManagerByRoleIdAndTeamId(paramsMap);
	}

	/**
	 * 启用/禁用项目 
	 * 启用/禁用当前项目(启用项目时如果存在上级组织或上上级组织为禁用状态则无法启用)
	 */
	@Override
	public void status(Integer id, Integer status) {
		Team team = teamMapper.selectByPrimaryKey(id);
		if (StringUtils.isEmpty(team)) {
//			throw new ProjectException("指定的项目不存在");
			return;
		}
		// 1:组织  2:项目
		if (RoleTypeEnum._1.getKey().equals(team.getType()+"")) {
//			throw new ProjectException("指定的项目不存在");
			return;
		}
		// 项目的所属组织
		Team firstUpperOrg = teamMapper.selectByPrimaryKey(team.getParentTeamId());
		if (StringUtils.isEmpty(firstUpperOrg)) {
			throw new ProjectException("项目所属组织不存在");
		}
		if (status==enable) {
			if (firstUpperOrg.getIsActive()==disable) {
				throw new ProjectException("所属组织为禁用状态，现无法启用该项目");
			}
			// 所有上级的code集合
			List<String> upLikeCodeList = orgAndProjectService.getUpLikeCode(firstUpperOrg.getCode());
			if (!upLikeCodeList.isEmpty()) {
				List<OrganizationVo> upperProjectList = teamMapper.findUpperOrgLikeParentCodeListAndStatus(upLikeCodeList, disable+"");
				if (!upperProjectList.isEmpty()) {
					throw new ProjectException("存在上级组织为禁用状态，现无法启用该项目");
				}
			}
		}
		// 更新项目状态
		teamMapper.updateTeamStatusByRoId(id, status);
		// 更新项目模块中间表状态
		teamModuleMapper.updateTeamModuleStatusByRoId(id, status);
	}

	/**
	 * 查询项目详情
	 * @param id
	 * @return
	 */
	@Override
	public TeamVo query(Integer id) {
		Team team = teamMapper.selectByPrimaryKey(id);
		if (StringUtils.isEmpty(team)) {
			throw new ProjectException("指定的项目不存在");
		}
		if (team.getType()!=2) {
			throw new ProjectException("参数非法，该参数对应的是组织");
		}
		// 当前登录人所在组织关联负责人通用角色
		Role role = orgAndProjectService.getManagerPublicRole(ProjectManagerKeyEnum._2.getKey());
		Map<String,Object> map = new HashMap<>();
		map.put("teamId", id); // 组织id 
		map.put("roleId", role.getRoleId()); // 组织负责人角色id
		map.put("roleStatus", role.getIsActive()); // 通用角色状态
		map.put("category", ProjectManagerKeyEnum._2.getKey()); // category
 		// 获取项目详情
		TeamVo teamVo = teamMapper.findProjectDeatilById(map);
		if (!StringUtils.isEmpty(teamVo.getTeamPic())) {
			String teamPic = serviceAddressHospitalpic + teamVo.getTeamPic();
			teamVo.setTeamPhone(teamPic);
		}
		List<String> allModuleList = new ArrayList<>();
		allModuleList.addAll(teamVo.getModules());
		allModuleList.addAll(teamVo.getHalfmodules());
		boolean isContainsApp = false;
		boolean isContainsProject = false;
		for (String code : allModuleList) {
			try {
				if (Integer.parseInt(code)<200) {
					// 项目端
					isContainsProject = true;
				} else {
					// app端
					isContainsApp = true;
				}
			} catch (NumberFormatException e) {
			}
		}
		
		if (isContainsApp) {
			teamVo.getHalfmodules().add(ProjectTypeEnum._1.getKey());
		}
		if (isContainsProject) {
			teamVo.getHalfmodules().add(ProjectTypeEnum._2.getKey());
		}
		return teamVo;
	}

	/**
	 * 查询项目列表
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public PageInfo<ProjectVo> list(TeamListDto teamListDto) {
		// 根据组织id查询下面的项目
		Team orgDto = teamMapper.findOrgById(teamListDto.getParentId());
		if (StringUtils.isEmpty(orgDto)) {
			throw new ProjectException("请求参数有误");
		}
		// 项目列表
		List<ProjectVo> proList = new ArrayList<>();
		// 当前登录人所在组织关联负责人通用角色
		Role managerRole = orgAndProjectService.getManagerPublicRole(ProjectManagerKeyEnum._2.getKey());
		PageHelper.startPage(teamListDto.getPage(), teamListDto.getPageSize());
		Map<String, Object> paramsMap = new HashMap<>();
		paramsMap.put("roleId", managerRole.getRoleId()); // 角色负责人
		paramsMap.put("category", ProjectManagerKeyEnum._2.getKey()); // 1: 负责人  2：项目经理
		paramsMap.put("roleStatus", managerRole.getIsActive()); // 通用角色状态
		
		PageHelper.startPage(teamListDto.getPage(), teamListDto.getPageSize());
		if (teamListDto.getContainChild()) {
			// 当前组织的所有下级项目
			String subLikeCode = orgAndProjectService.getSubLikeCode(orgDto.getCode());
			paramsMap.put("subLikeCode", subLikeCode); 
			proList = teamMapper.findProjectListByCodeLike(paramsMap);
		} else {
			paramsMap.put("parentId", teamListDto.getParentId()); 
			// 下一级列表
			proList = teamMapper.findFirstSubProjectListByParentId(paramsMap);
		}
		PageInfo<ProjectVo> pageInfo = new PageInfo(proList);
		return pageInfo;
	}

	/**
	 * 新增项目校验信息
	 */
	private void checkAddProject(ProjectVo projectVo, Team org) {
		if (StringUtils.isEmpty(org)) {
			throw new ProjectException("选择组织不存在或已被删除");
		}
		// 当前登录人是否有创建权限项目权限（例如：登录人为三级组织不能编辑平级和上级组织下的项目） 当前登录人所在组织和项目所属组织对比
		int authStatus = orgAndProjectService.orgRelationship(org.getCode());
		if (!(-1==authStatus)) {
			throw new ProjectException("当前登录人没有对该项目的创建权限");
		}
		// 上级组织层级
		int parentLevel = 0;
		if (!StringUtils.isEmpty(org)) {
			// 逻辑状态 1正常，2禁用，3 删除，目前没有删除操作先保留判断。
			if (org.getIsActive()==3) {
				throw new ProjectException("选择组织已被删除");
			}
//			if (org.getIsActive()==2) {
//				throw new ProjectException("选择禁用的组织，不允许新增新的项目");
//			}
			parentLevel = orgAndProjectService.getOrgLevel(org.getCode());
			// 正常 
			if (parentLevel>=5) {
				throw new ProjectException("组织层级不能超过5级");
			}
		} else {
			throw new ProjectException("上级组织不存在");
		}
		// 检查项目名称是否唯一(只约束同级)
		ProjectVo pro = teamMapper.findFirstSubProjectByName(projectVo);
		if (!StringUtils.isEmpty(pro)) {
			throw new ProjectException("该项目已存在，请勿重复提交");
		}
	}
	/**
	 * 校验编辑项目参数是否异常
	 * @param projectVo 编辑项目入参
	 * @param team 项目基本信息
	 */
	private void checkEditProject(ProjectVo projectVo, Team team) {
		// 当前登录人是否有创建权限项目权限（例如：登录人为三级组织不能编辑平级和上级组织下的项目） 当前登录人所在组织和项目所属组织对比
		int authStatus = orgAndProjectService.orgRelationship(projectVo.getOrgId());
		if (!(-1==authStatus)) {
			throw new ProjectException("当前登录人没有对该项目的编辑权限");
		}
		// 检查项目名称是否唯一
		ProjectVo pro = teamMapper.findFirstSubProjectByName(projectVo);
		if (!StringUtils.isEmpty(pro)) {
			throw new ProjectException("该项目已存在，请勿重复提交");
		}
		if (StringUtils.isEmpty(team)) {
			throw new ProjectException("参数异常，指定项目不存在");
		}
		if (team.getParentTeamId()!=projectVo.getOrgId()) {
			// 后期有允许修改上级组织的需求，可以逻辑删除旧组织，复制到新组织下
			throw new ProjectException("不允许修改上级组织");
		}
	}
	/**
	 * 保存项目
	 * @param projectVo
	 * @param org
	 */
	private void save(ProjectVo projectVo, Team org) {
		// 获得登录人信息
		LoginDataVo courrentUser = LocalManager.getVal(LocalManagerType.LOGIN_DATA);
		int size = 0;
		Map<String,Object> paramsMap = new HashMap<>();
		paramsMap.put("parentId", projectVo.getOrgId());
		paramsMap.put("type", TeamTypeEnum._2.getKey());
		// 查询组织下的所有项目
		List<Team> firstSubProjectList = teamMapper.selectFirstAllStatusSubOrgOrProList(paramsMap);
		if (!firstSubProjectList.isEmpty()) {
			size = firstSubProjectList.size();
		}
		if (size>=999) {
			throw new ProjectException("无法添加该项目，该层级项目数量已达上限");
		}
		// 项目创建人
		projectVo.setCreateBy(courrentUser.getUser().getUserId());
		// 项目状态和选择组织状态保持一致，目前虽然控制禁用组织不能新建项目，以防后期修改。
		projectVo.setStatus(org.getIsActive()+"");
		// 设置组织/项目所属一级组织ID
		projectVo.setFirstOrg(courrentUser.getUser().getFirstOrg()+"");
		// 项目code
		projectVo.setCode(orgAndProjectService.getNextProjectCode(org.getCode(), size));
		if (!StringUtils.isEmpty(projectVo.getTeamPic())) {
			String teamPic = projectVo.getTeamPic();
			projectVo.setTeamPhone(teamPic.replaceAll(serviceAddressHospitalpic, ""));
		}
		// 保存项目基本信息
		int proNum = teamMapper.addProjectBase(projectVo);
		if (proNum<1) {
			throw new ProjectException("保存项目基本信息失败");
		}
		if (!projectVo.getModules().isEmpty()) {
			// 移除项目端和app端code
			projectVo.getModules().remove(ProjectTypeEnum._1.getKey());
			projectVo.getModules().remove(ProjectTypeEnum._2.getKey());
			
			// 批量保存项目全选模块信息
			int proModule = teamModuleMapper.addProjectAllModuleBase(projectVo);
			if (proModule<1) {
				throw new ProjectException("保存项目模块关联关系失败");
			}
		} 
		if (!projectVo.getHalfmodules().isEmpty()) {
			// 移除项目端和app端code
			projectVo.getHalfmodules().remove(ProjectTypeEnum._1.getKey());
			projectVo.getHalfmodules().remove(ProjectTypeEnum._2.getKey());
			
			// 批量保存项目全选模块信息
			int proModule = teamModuleMapper.addProjectHalfModuleBase(projectVo);
			if (proModule<1) {
				throw new ProjectException("保存项目模块关联关系失败");
			}
		} 
		// 保存项目与项目经理关系
		if (!StringUtils.isEmpty(projectVo.getManager())) {
			// 查询相关联的项目经理角色
			Role role = orgAndProjectService.getManagerPublicRole(ProjectManagerKeyEnum._2.getKey());
			// 保存项目经理
			UserTeam bean = new UserTeam();
			bean.setUserId(Integer.parseInt(projectVo.getManager()));
			bean.setRoleId(role.getRoleId()); // 角色id
			bean.setTeamId(projectVo.getId()); // 组织id
			bean.setCategory(ProjectManagerKeyEnum._2.getKey()); // 标识组织/项目模块获得负责人，项目经理角色：1:负责人 2:项目经理  null：其他
			bean.setIsActive(role.getIsActive()); // 逻辑状态 1正常，2禁用，3 删除
			bean.setCreateTime(new Date()); // 创建时间
			userTeamMapper.insert(bean);
		}
	} 
	/**
	 * 更新项目以及项目模块信息
	 * @param projectVo 编辑项目入参
	 * @param team 数据库中项目基本信息
	 */
	private void updateProject(ProjectVo projectVo, Team team) {
		// 获得登录人信息
		LoginDataVo courrentUser = LocalManager.getVal(LocalManagerType.LOGIN_DATA);
		if (!StringUtils.isEmpty(projectVo.getTeamPic())) {
			String teamPic = projectVo.getTeamPic();
			projectVo.setTeamPhone(teamPic.replaceAll(serviceAddressHospitalpic, ""));
		}
		// 项目更新人
		projectVo.setCreateBy(courrentUser.getUser().getUserId());
		// 和更新前的状态保持一致
		projectVo.setStatus(team.getIsActive()+"");
		// 更新项目基本信息
		int num = teamMapper.updateProjectBase(projectVo);
		if (num<1) {
			throw new ProjectException("更新项目基本信息失败");
		}
		
		// 批量更新组织模块信息
		// 对比需要删除和新增的模块
		Set<String> removeModuleSet = new HashSet<>();
		Set<String> addAllModuleSet = new HashSet<>();
		Set<String> addHalfModuleSet = new HashSet<>();
		{
			Map<String, String> paramsMap = new HashMap<>();
			paramsMap.put("projectId", projectVo.getId()+"");
			paramsMap.put("status", team.getIsActive()+"");
			// 是否全选: 1: 全选  2：半选
			paramsMap.put("isHalf", ModuleStatusEnum._1.getKey());
			List<TeamModule> teamAllModuleList = teamModuleMapper.findAllModuleByProjectId(paramsMap);
			
			// 全选模块比较
			Map<String, Set<String>> allMap = compareList(teamAllModuleList, projectVo.getModules());
			removeModuleSet.addAll(allMap.get("removeModuleSet"));
			addAllModuleSet.addAll(allMap.get("addModuleSet"));
			
			// 是否全选: 1: 全选  2：半选
			paramsMap.put("isHalf", ModuleStatusEnum._2.getKey());
			List<TeamModule> teaHalfmModuleList = teamModuleMapper.findAllModuleByProjectId(paramsMap);
			// 半选模块比较
			Map<String, Set<String>> halfMap = compareList(teaHalfmModuleList, projectVo.getHalfmodules());
			removeModuleSet.addAll(halfMap.get("removeModuleSet"));
			addHalfModuleSet.addAll(halfMap.get("addModuleSet"));
		}
		
		if (!removeModuleSet.isEmpty()) {
			int count = teamModuleMapper.deleteModuleByProjectIdAndModuleId(projectVo.getId(), removeModuleSet);
			if (count<1) {
				throw new ProjectException("删除项目和可用模块关联信息失败");
			}
		}
		// 和更新前的状态保持一致
		projectVo.setStatus(team.getIsActive()+"");
		if (!addAllModuleSet.isEmpty()) {
			int count = teamModuleMapper.addAllModuleByProjectIdAndModuleId(projectVo, addAllModuleSet);
			if (count<1) {
				throw new OrganizationException("删除项目和可用模块关联信息失败");
			}
		}
		if (!addHalfModuleSet.isEmpty()) {
			int count = teamModuleMapper.addHalfModuleByProjectIdAndModuleId(projectVo, addHalfModuleSet);
			if (count<1) {
				throw new OrganizationException("组织可用模块信息保存失败");
			}
		}
	}
	
	/**
	 * 比较两个集合
	 * @param oldTeamModuleList 数据库保存的team_module
	 * @param newModuleList 编辑之后的team_module
	 */
	private Map<String, Set<String>> compareList(List<TeamModule> oldTeamModuleList, List<String> newModuleList) {
		Map<String, Set<String>> resultMap = new HashMap<>();
		Set<String> removeModuleSet = new HashSet<>();
		oldTeamModuleList.forEach(module->{
			removeModuleSet.add(module.getModuleId()+"");
		});
		
		// 移除项目端和App端的模块code
		if (!newModuleList.isEmpty()) {
			newModuleList.remove(ProjectTypeEnum._1.getKey());
			newModuleList.remove(ProjectTypeEnum._2.getKey());
		}
		
		Set<String> copySaveModuleSet = new HashSet<>(removeModuleSet);
		Set<String> addModuleSet = new HashSet<>(newModuleList);
		
		// 需要删除的集合
		removeModuleSet.removeAll(addModuleSet);
		// 需要增加的集合
		addModuleSet.removeAll(copySaveModuleSet);
		resultMap.put("removeModuleSet", removeModuleSet);
		resultMap.put("addModuleSet", addModuleSet);
		return resultMap;
	}

}
